//
// Created by 32416 on 2022/2/26.
//

int open_clientfd (char* hostname, char* port){
    int clientfd;
    struct addrinfo hints, *listp, *p;

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_socketype = SOCK_STREAM;   //将getaddrinfo返回的套接字链表里，一个地址对应端口
    hints.ai_flags = AI_NUMERICSERV;    //强制使用端口号，默认的话是端口号和协议都可以
    hints.ai_flags |= AI_ADDRCONFIG;    //使用连接推荐？？、
    Getaddrinfo(hostname, port, &hints, &listp);    //第四个参数是一个指针，返回的是一个链表

    for (p = listp; p; p = p->ai_next) {
        if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
            continue;
        }
        if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break;
        Close(clientfd);
    }
    Freeaddrinfo(listp);
    if (!p) return -1;
    else return clientfd;
}

int open_listenfd(char* port) {
    int listenfd;
    struct addrinfo hints, *listp, *p;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
    // AI_PASSIVE  使得返回为一个通配符地址，此时host应该是NULL，告诉系统这是一个监听socket
    hints.ai_flags |= AI_NUMERICSER;
    Getaddrinfo(NULL, port, &hints, &lisp);

    for (p = listp; p; p = p->ai_next) {
        if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
            continue;
        // Setsockopt(); 预防bind失败
        if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) {
            break;
        }
        Close(listenfd);
    }
    Freeaddrinfo(listp);
    if (!p) return -1;
    // 开始listen
    if (listen(listenfd, LISTENQ) < 0) {
        Close(listenfd);
        return -1;
    }
    return listenfd;
}

